package com.kongjs.common.datasource.config;


import com.kongjs.common.datasource.component.DataSourceKeyBean;
import com.kongjs.common.datasource.component.DynamicDataSource;
import com.kongjs.common.datasource.component.DynamicDataSourceContextHolder;
import com.kongjs.common.datasource.component.DynamicDataSourceRegistrar;
import com.kongjs.common.datasource.factory.DataSourceFactory;
import com.kongjs.common.datasource.properties.DataSourceProperties;
import com.kongjs.common.datasource.properties.DynamicDatasourceProperties;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.jdbc.datasource.lookup.BeanFactoryDataSourceLookup;
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ComponentScan("com.kongjs.dynamic.datasource")
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
@EnableConfigurationProperties(DynamicDatasourceProperties.class)
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement
public class DataSourceConfig {
    private static final Logger log = LoggerFactory.getLogger(DataSourceConfig.class);
    @Resource
    private DynamicDatasourceProperties dynamicDatasourceProperties;
    @Resource
    private DynamicDataSourceRegistrar dynamicDataSourceRegistrar;

    /**
     * 支持数据源通过beanName从spring上下文获取
     */
    @Bean
    @ConditionalOnMissingBean(DataSourceLookup.class)
    public DataSourceLookup dataSourceLookup() {
        return new BeanFactoryDataSourceLookup();
    }

    @Bean
    @ConditionalOnMissingBean(DataSourceKeyBean.class)
    public DataSourceKeyBean dataSourceKeyBean() {
        return DynamicDataSourceContextHolder::getDataSourceKey;
    }

    /**
     * 动态数据源
     */
    @Bean("dynamicDataSource")
    @ConditionalOnMissingBean(DynamicDataSource.class)
    public DynamicDataSource dynamicDataSource(DataSourceKeyBean dataSourceKeyBean, DataSourceLookup dataSourceLookup) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource(dataSourceKeyBean);
        Map<Object, Object> targetDataSources = new HashMap<>();
        DataSource defaultTargetDataSource = null;
        List<DataSourceProperties> dynamic = dynamicDatasourceProperties.getDynamic();
        if (!CollectionUtils.isEmpty(dynamic)) {
            for (DataSourceProperties dataSourceProperties : dynamic) {
                DataSource dataSource = DataSourceFactory.createDatasource(dataSourceProperties);
                String key = dynamicDataSource.getDataSourcePrefix() + dataSourceProperties.getName();
                DataSource dataSourceBean = dynamicDataSourceRegistrar.registerDataSource(key, dataSource);
                targetDataSources.put(key, dataSourceBean);
                log.info("加载动态数据源:{} {}", key, dataSourceBean);
                if (dataSourceProperties.isDefault()) {
                    defaultTargetDataSource = dataSourceBean;
                    log.info("加载默认数据源:{} {}", key, dataSourceBean);
                }
            }
        }
        Assert.notNull(defaultTargetDataSource, "默认数据源未设置");
        dynamicDataSource.setLenientFallback(false);
        dynamicDataSource.setDataSourceLookup(dataSourceLookup);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(defaultTargetDataSource);
        return dynamicDataSource;
    }


    /**
     * 事务
     */
    @Bean("dynamicDataSourceTransactionManager")
    public PlatformTransactionManager dynamicDataSourceTransactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    /**
     * 事务切换代理
     */
    @Bean
    @Primary
    public DataSource dynamicDataSourceTransactionAwareDataSource(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
        return new TransactionAwareDataSourceProxy(dynamicDataSource);
    }
}
